package com.rose.springbootgeneratefile.api;

import com.rose.springbootgeneratefile.config.Context;
import com.rose.springbootgeneratefile.config.JavaModelGeneratorConfiguration;
import com.rose.springbootgeneratefile.config.PropertyHolder;
import com.rose.springbootgeneratefile.config.TableConfiguration;
import com.rose.springbootgeneratefile.utils.StringUtility;

import java.util.*;

public abstract class IntrospectedTable {
    protected TargetRuntime targetRuntime;
    protected Map<String, Object> attributes;

    public enum TargetRuntime {
        /** The MYBATI s3. */
        MYBATIS3
    }
    public IntrospectedTable() {
        super();
        baseColumns = new ArrayList<IntrospectedColumn>();
        blobColumns = new ArrayList<IntrospectedColumn>();
    }

    public IntrospectedTable(TargetRuntime targetRuntime) {
        super();
        this.targetRuntime = targetRuntime;
        primaryKeyColumns = new ArrayList<IntrospectedColumn>();
        baseColumns = new ArrayList<IntrospectedColumn>();
        blobColumns = new ArrayList<IntrospectedColumn>();
        attributes = new HashMap<String, Object>();
        internalAttributes = new HashMap<IntrospectedTable.InternalAttribute, String>();
    }
    protected enum InternalAttribute {

        /** The attr dao implementation type. */
        ATTR_DAO_IMPLEMENTATION_TYPE,

        /** The attr dao interface type. */
        ATTR_DAO_INTERFACE_TYPE,

        /** The attr primary key type. */
        ATTR_PRIMARY_KEY_TYPE,

        /** The attr base record type. */
        ATTR_BASE_RECORD_TYPE,

        /** The attr record with blobs type. */
        ATTR_RECORD_WITH_BLOBS_TYPE,

        /** The attr example type. */
        ATTR_EXAMPLE_TYPE,

        /** The ATT r_ ibati s2_ sq l_ ma p_ package. */
        ATTR_IBATIS2_SQL_MAP_PACKAGE,

        /** The ATT r_ ibati s2_ sq l_ ma p_ fil e_ name. */
        ATTR_IBATIS2_SQL_MAP_FILE_NAME,

        /** The ATT r_ ibati s2_ sq l_ ma p_ namespace. */
        ATTR_IBATIS2_SQL_MAP_NAMESPACE,

        /** The ATT r_ mybati s3_ xm l_ mappe r_ package. */
        ATTR_MYBATIS3_XML_MAPPER_PACKAGE,

        /** The ATT r_ mybati s3_ xm l_ mappe r_ fil e_ name. */
        ATTR_MYBATIS3_XML_MAPPER_FILE_NAME,

        /** also used as XML Mapper namespace if a Java mapper is generated. */
        ATTR_MYBATIS3_JAVA_MAPPER_TYPE,

        /** used as XML Mapper namespace if no client is generated. */
        ATTR_MYBATIS3_FALLBACK_SQL_MAP_NAMESPACE,

        /** The attr fully qualified table name at runtime. */
        ATTR_FULLY_QUALIFIED_TABLE_NAME_AT_RUNTIME,

        /** The attr aliased fully qualified table name at runtime. */
        ATTR_ALIASED_FULLY_QUALIFIED_TABLE_NAME_AT_RUNTIME,

        /** The attr count by example statement id. */
        ATTR_COUNT_BY_EXAMPLE_STATEMENT_ID,

        /** The attr delete by example statement id. */
        ATTR_DELETE_BY_EXAMPLE_STATEMENT_ID,

        /** The attr delete by primary key statement id. */
        ATTR_DELETE_BY_PRIMARY_KEY_STATEMENT_ID,

        /** The attr insert statement id. */
        ATTR_INSERT_STATEMENT_ID,

        /** The attr insert selective statement id. */
        ATTR_INSERT_SELECTIVE_STATEMENT_ID,

        /** The attr select all statement id. */
        ATTR_SELECT_ALL_STATEMENT_ID,

        /** The attr select by example statement id. */
        ATTR_SELECT_BY_EXAMPLE_STATEMENT_ID,

        /** The attr select by example with blobs statement id. */
        ATTR_SELECT_BY_EXAMPLE_WITH_BLOBS_STATEMENT_ID,

        /** The attr select by primary key statement id. */
        ATTR_SELECT_BY_PRIMARY_KEY_STATEMENT_ID,

        /** The attr update by example statement id. */
        ATTR_UPDATE_BY_EXAMPLE_STATEMENT_ID,

        /** The attr update by example selective statement id. */
        ATTR_UPDATE_BY_EXAMPLE_SELECTIVE_STATEMENT_ID,

        /** The attr update by example with blobs statement id. */
        ATTR_UPDATE_BY_EXAMPLE_WITH_BLOBS_STATEMENT_ID,

        /** The attr update by primary key statement id. */
        ATTR_UPDATE_BY_PRIMARY_KEY_STATEMENT_ID,

        /** The attr update by primary key selective statement id. */
        ATTR_UPDATE_BY_PRIMARY_KEY_SELECTIVE_STATEMENT_ID,

        /** The attr update by primary key with blobs statement id. */
        ATTR_UPDATE_BY_PRIMARY_KEY_WITH_BLOBS_STATEMENT_ID,

        /** The attr base result map id. */
        ATTR_BASE_RESULT_MAP_ID,

        /** The attr result map with blobs id. */
        ATTR_RESULT_MAP_WITH_BLOBS_ID,

        /** The attr example where clause id. */
        ATTR_EXAMPLE_WHERE_CLAUSE_ID,

        /** The attr base column list id. */
        ATTR_BASE_COLUMN_LIST_ID,

        /** The attr blob column list id. */
        ATTR_BLOB_COLUMN_LIST_ID,

        /** The ATT r_ mybati s3_ updat e_ b y_ exampl e_ wher e_ claus e_ id. */
        ATTR_MYBATIS3_UPDATE_BY_EXAMPLE_WHERE_CLAUSE_ID,

        /** The ATT r_ mybati s3_ sq l_ provide r_ type. */
        ATTR_MYBATIS3_SQL_PROVIDER_TYPE
    }
    /**
     *  公共类型
     *  */
    protected List<IntrospectedColumn> baseColumns;

    /**
     * 大数据类型
     * */
    protected List<IntrospectedColumn> blobColumns;
    /**
     * 唯一key列类型
     */
    protected List<IntrospectedColumn> primaryKeyColumns;
    /**
     * 上下文对象
     *
     */
    protected Context context;
    /**
     *完全合格的表格
     */
    protected FullyQualifiedTable fullyQualifiedTable;
    /**
     * table标签配置类
     */
    protected TableConfiguration tableConfiguration;
    /**
     * 备注内容
     */
    protected String remarks;

    protected Map<InternalAttribute, String> internalAttributes;

    public void setBaseRecordType(String baseRecordType) {
        internalAttributes.put(InternalAttribute.ATTR_BASE_RECORD_TYPE,
                baseRecordType);
    }
    public String getBaseRecordType() {
        return internalAttributes.get(InternalAttribute.ATTR_BASE_RECORD_TYPE);
    }
    public List<IntrospectedColumn> getPrimaryKeyColumns() {
        return primaryKeyColumns;
    }


    public List<IntrospectedColumn> getBaseColumns() {
        return baseColumns;
    }


    public List<IntrospectedColumn> getBlobColumns() {
        return blobColumns;
    }


    public String getRemarks() {
        return remarks;
    }

    public void setRemarks(String remarks) {
        this.remarks = remarks;
    }

    public TableConfiguration getTableConfiguration() {
        return tableConfiguration;
    }

    public void setTableConfiguration(TableConfiguration tableConfiguration) {
        this.tableConfiguration = tableConfiguration;
    }

    public FullyQualifiedTable getFullyQualifiedTable() {
        return fullyQualifiedTable;
    }

    public void setFullyQualifiedTable(FullyQualifiedTable fullyQualifiedTable) {
        this.fullyQualifiedTable = fullyQualifiedTable;
    }

    public Context getContext() {
        return context;
    }

    public void setContext(Context context) {
        this.context = context;
    }

    public String getTableConfigurationProperty(String property) {
        return tableConfiguration.getProperty(property);
    }


    private boolean isSubPackagesEnabled(PropertyHolder propertyHolder) {
        return StringUtility.isTrue(propertyHolder.getProperty(PropertyRegistry.ANY_ENABLE_SUB_PACKAGES));
    }

    protected String calculateJavaModelPackage() {
        JavaModelGeneratorConfiguration config = context
                .getJavaModelGeneratorConfiguration();

        StringBuilder sb = new StringBuilder();
        sb.append(config.getTargetPackage());
        sb.append(fullyQualifiedTable.getSubPackageForModel(isSubPackagesEnabled(config)));

        return sb.toString();
    }

    protected void calculateModelAttributes() {
        String pakkage = calculateJavaModelPackage();

        StringBuilder sb = new StringBuilder();
//        sb.append(pakkage);
//        sb.append('.');
//        sb.append(fullyQualifiedTable.getDomainObjectName());
//        sb.append("Key"); //$NON-NLS-1$
//        setPrimaryKeyType(sb.toString());

        sb.setLength(0);
        sb.append(pakkage);
        sb.append('.');
        sb.append(fullyQualifiedTable.getDomainObjectName());
        setBaseRecordType(sb.toString());

//        sb.setLength(0);
//        sb.append(pakkage);
//        sb.append('.');
//        sb.append(fullyQualifiedTable.getDomainObjectName());
//        sb.append("WithBLOBs"); //$NON-NLS-1$
//        setRecordWithBLOBsType(sb.toString());

//        sb.setLength(0);
//        sb.append(pakkage);
//        sb.append('.');
//        sb.append(fullyQualifiedTable.getDomainObjectName());
//        sb.append("Example"); //$NON-NLS-1$
//        setExampleType(sb.toString());
    }

    /**
     * 添加列
     * @param introspectedColumn
     */
    public void addColumn(IntrospectedColumn introspectedColumn) {
        if (introspectedColumn.isBLOBColumn()) {
            blobColumns.add(introspectedColumn);
        } else {
            baseColumns.add(introspectedColumn);
        }

        introspectedColumn.setIntrospectedTable(this);
    }

    /**
     * 是否有构造函数
     * @return
     */
    public boolean isConstructorBased() {
        if (isImmutable()) {
            return true;
        }
        Properties properties;
        if (tableConfiguration.getProperties().containsKey(PropertyRegistry.ANY_CONSTRUCTOR_BASED)) {
            properties = tableConfiguration.getProperties();
        } else {
            properties = context.getJavaModelGeneratorConfiguration().getProperties();
        }

        return StringUtility.isTrue(properties.getProperty(PropertyRegistry.ANY_CONSTRUCTOR_BASED));
    }

    /**
     * 是否不可变
     * @return
     */
    public boolean isImmutable() {
        Properties properties;

        if (tableConfiguration.getProperties().containsKey(PropertyRegistry.ANY_IMMUTABLE)) {
            properties = tableConfiguration.getProperties();
        } else {
            properties = context.getJavaModelGeneratorConfiguration().getProperties();
        }

        return StringUtility.isTrue(properties.getProperty(PropertyRegistry.ANY_IMMUTABLE));
    }
    public void initialize() {
//        calculateJavaClientAttributes();
        calculateModelAttributes();
//        calculateXmlAttributes();
//
//        if (tableConfiguration.getModelType() == ModelType.HIERARCHICAL) {
//            rules = new HierarchicalModelRules(this);
//        } else if (tableConfiguration.getModelType() == ModelType.FLAT) {
//            rules = new FlatModelRules(this);
//        } else {
//            rules = new ConditionalModelRules(this);
//        }

//        context.getPlugins().initialized(this);
    }

    /**
     * 获取所有字段
     * @return
     */
    public List<IntrospectedColumn> getAllColumns() {
        List<IntrospectedColumn> answer = new ArrayList<IntrospectedColumn>();
        answer.addAll(primaryKeyColumns);
        answer.addAll(baseColumns);
        answer.addAll(blobColumns);

        return answer;
    }

    public abstract void calculateGenerators();

    public abstract List<GeneratedJavaFile> getGeneratedJavaFiles();


    public abstract List<GeneratedXmlFile> getGeneratedXmlFiles();

}
